package com.derbysoft.dswitch.adapter.ihg.dswitch2.service.impl;

import com.derbysoft.dswitch.adapter.ihg.dswitch2.HotelProviderService;
import com.derbysoft.dswitch.adapter.ihg.dto.OTAHotelAvailRS;
import com.derbysoft.dswitch.adapter.ihg.dto.OTAHotelResRS;
import com.derbysoft.dswitch.adapter.ihg.dto.RoomRate;
import com.derbysoft.dswitch.adapter.ihg.dto.Tax;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

/**
 * Created by: jason
 * Date: 2012-06-07
 */
public abstract class ReservationRateHelper {

    private static final Log LOGGER = LogFactory.getLog(ReservationRateHelper.class);

    public static boolean check(OTAHotelAvailRS otaHotelAvailRS, OTAHotelResRS otaHotelResRS,
                                String ratePlanCode, String roomTypeCode) {
        RoomRate roomRate = findRoomRate(otaHotelAvailRS, ratePlanCode, roomTypeCode);
        if (roomRate == null) {
            return false;
        }

        BigDecimal reservationBaseRate = otaHotelResRS.getHotelReservations().getHotelReservation().get(0).getServices().getService()
                .get(0).getPrice().get(0).getBase().getAmountBeforeTax();

        BigDecimal additionalGuestAmountAndTotalTax = otaHotelResRS.getHotelReservations().getHotelReservation()
                .get(0).getServices().getService().get(0).getPrice().get(0).getBase().getTaxes().getAmount();

        BigDecimal avgAmount = getAmountByTaxCode(HotelProviderService.AVG_TAX, roomRate);
        if (avgAmount != null && rounding(avgAmount).compareTo(rounding(reservationBaseRate)) != 0) {
            LOGGER.warn(String.format("AVGAmount differ ReservationBaseRate: [%s] != [%s]", avgAmount, reservationBaseRate));
            return true;
        }
        checkTax(additionalGuestAmountAndTotalTax, roomRate);
        return false;
    }

    private static void checkTax(BigDecimal additionalGuestAmountAndTotalTax, RoomRate roomRate) {
        BigDecimal totalTax = getAmountByTaxCode(HotelProviderService.TTX_TAX, roomRate);
        if (totalTax != null && rounding(totalTax).compareTo(rounding(additionalGuestAmountAndTotalTax)) == 0) {
            return;
        }
        BigDecimal totalAmountAfterTax = getAmountByTaxCode(HotelProviderService.TMT_TAX, roomRate);
        BigDecimal totalBaseRate = getAmountByTaxCode(HotelProviderService.TTR_TAX, roomRate);
        if (totalAmountAfterTax == null || totalBaseRate == null) {
            return;
        }
        BigDecimal totalBaseTax = totalAmountAfterTax.subtract(totalBaseRate);
        if (rounding(totalBaseTax).compareTo(additionalGuestAmountAndTotalTax) != 0) {
            LOGGER.warn(String.format("Total Tax is different from AdditionalGuestAmountAndTotalTax:[%s] != [%s]",
                    totalBaseTax, additionalGuestAmountAndTotalTax));
        }
    }

    private static BigDecimal rounding(BigDecimal amount) {
        return amount.setScale(2, RoundingMode.HALF_UP);
    }

    private static RoomRate findRoomRate(OTAHotelAvailRS otaHotelAvailRS,
                                         String ratePlanCode, String roomTypeCode) {
        String newRoomTypeCode = roomTypeCode + ratePlanCode;
        for (RoomRate roomRate : otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate()) {
            if (roomRate.getRatePlanCode().equals(ratePlanCode) && roomRate.getRoomTypeCode().equals(newRoomTypeCode)) {
                return roomRate;
            }
        }
        return null;
    }

    private static BigDecimal getAmountByTaxCode(String code, RoomRate roomRate) {
        List<Tax> taxes = roomRate.getRates().getRate().get(0).getTotal().getTaxes().getTax();
        for (Tax tax : taxes) {
            if (tax.getCode().equals(code)) {
                return tax.getAmount();
            }
        }
        return null;
    }
}
